package com.light.component;

import atlantafx.base.theme.Styles;
import com.light.exception.AuthException;
import com.light.exception.JGitException;
import com.light.model.GitAuthInfo;
import com.light.model.GitProject;
import com.light.thread.FxAsyncTask;
import com.light.util.DateUtils;
import com.light.util.FxApplicationContextUtils;
import com.light.util.H2PoolUtils;
import com.light.util.JGitUtils;
import javafx.beans.property.*;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.kordamp.ikonli.bootstrapicons.BootstrapIcons;
import org.kordamp.ikonli.javafx.FontIcon;

import java.io.File;
import java.util.Date;

import static com.light.util.JGitUtils.getAuthor;
import static com.light.util.JGitUtils.getRepoName;

public class DownloadHBox extends HBox {
    private final String remoteUrl;
    private final File localRepoFile;
    private final Button retryButton;
    private final ProgressBar progressBar = new ProgressBar(0.0);
    private final Label text = new Label();
    private final CustomProgressMonitor customProgressMonitor = new CustomProgressMonitor(progressBar, null, text);
    private CredentialsProvider provider;

    private boolean isAuthException = false;

    /**
     * 构造方法
     *
     * @param remoteUrl     远程仓库路径
     * @param localRepoFile 本地克隆地址
     * @param authInfo      权限
     */
    public DownloadHBox(String remoteUrl, File localRepoFile, GitAuthInfo authInfo) {
        super(10);
        setAlignment(Pos.CENTER);

        this.remoteUrl = remoteUrl;
        this.localRepoFile = localRepoFile;

        var label = new Label(getRepoName(remoteUrl));
        progressBar.setMaxWidth(300);
        progressBar.setMinHeight(3d);
        var vbox = new VBox(5, label, progressBar, text);

        retryButton = new Button(null, new FontIcon(BootstrapIcons.PLAY));
        retryButton.getStyleClass().addAll(Styles.BUTTON_ICON, Styles.FLAT, Styles.ACCENT);
        retryButton.setVisible(false);

        Button removeButton = new Button(null, new FontIcon(BootstrapIcons.X));
        removeButton.getStyleClass().addAll(Styles.BUTTON_ICON, Styles.FLAT, Styles.ACCENT);
        getChildren().addAll(vbox, retryButton, removeButton);
        HBox.setHgrow(vbox, Priority.ALWAYS);
        setPadding(new Insets(5, 2, 5, 2));

        // 监控器和权限
        provider = JGitUtils.createCredential(authInfo.username(), authInfo.password());

        retryButton.setOnMouseClicked(event -> cloneRepo(provider, true));
        removeButton.setOnMouseClicked(event -> {
            FxApplicationContextUtils.DOWNLOAD_LIST.remove(this);
            // 更新下载数量-1
            FxApplicationContextUtils.DOWNLOAD_PROPERTY.set(String.valueOf(FxApplicationContextUtils.DOWNLOAD_NUMBER.decrementAndGet()));
        });
        // 更新下载数量+1
        FxApplicationContextUtils.DOWNLOAD_PROPERTY.set(String.valueOf(FxApplicationContextUtils.DOWNLOAD_NUMBER.incrementAndGet()));
        cloneRepo(provider, false);
    }

    /**
     * 克隆项目
     *
     * @param provider 权限
     * @param retry    重试标识
     */
    public void cloneRepo(CredentialsProvider provider, boolean retry) {
        this.provider = provider;
        AuthenticationPane authPane = AuthenticationPane.getInstance();

        Task<GitProject> task = FxAsyncTask.runOnceBack(System.currentTimeMillis(), "克隆项目",
                () -> {
                    if (retry) {
                        deleteFiles(localRepoFile);
                        retryButton.setVisible(false);
                    }

                    try {
                        // 开始下载
                        String branch = JGitUtils.cloneRepo(remoteUrl, localRepoFile, provider, customProgressMonitor);
                        // 下载完成入库
                        String name = getRepoName(remoteUrl);
                        String author = getAuthor(remoteUrl);
                        String local = localRepoFile.getAbsolutePath();
                        GitProject newProject = new GitProject(new SimpleIntegerProperty(0),
                                new SimpleStringProperty(name),
                                new SimpleStringProperty(author),
                                new SimpleStringProperty(branch),
                                DateUtils.formatDateTime(new Date()),
                                new SimpleStringProperty(DateUtils.formatDateTime(new Date())),
                                remoteUrl,
                                new SimpleStringProperty(local),
                                new SimpleStringProperty(),
                                new SimpleStringProperty(),
                                new SimpleIntegerProperty(0),
                                new SimpleDoubleProperty(0.0),
                                new SimpleBooleanProperty(false)
                        );
                        H2PoolUtils.insertProjectInfo(newProject);

                        return newProject;
                    } catch (AuthException e) {
                        isAuthException = true;
                        authPane.refreshData(remoteUrl, (username, password) -> cloneRepo(JGitUtils.createCredential(username, password), true));
                        throw new AuthException();
                    } catch (Exception e) {
                        isAuthException = false;
                        throw new JGitException();
                    }
                },
                success -> {
                    FxApplicationContextUtils.GIT_PROJECT_OBSERVABLE_LIST.add(success);
                    // 更新下载数量-1
                    FxApplicationContextUtils.DOWNLOAD_PROPERTY.set(String.valueOf(FxApplicationContextUtils.DOWNLOAD_NUMBER.decrementAndGet()));
                },
                fail -> {
                    if (authPane != null && isAuthException) {
                        authPane.show((Scene) FxApplicationContextUtils.GLOBAL_CONTEXT_MAP.get("scene"));
                    }
                    retryButton.setVisible(true);
                });
    }

    private void deleteFiles(File folder) {
        if (folder.exists()) {
            // 获取文件夹中的所有文件和子文件夹
            File[] files = folder.listFiles();

            if (files != null) {
                for (File file : files) {
                    // 如果是文件，则直接删除
                    if (file.isFile()) {
                        file.delete();
                    }
                    // 如果是文件夹，则递归调用deleteFiles方法删除文件夹下的文件
                    else if (file.isDirectory()) {
                        deleteFiles(file);
                    }
                }
            }
        }
    }
}
